package com.lagou.server.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSON;
import com.lagou.server.datasource.ZkDataSourceProperties;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.aopalliance.intercept.Interceptor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.lang.reflect.Field;

/**
 * @author Kirito
 * @description:
 * @date 2020/06/04
 */
@Configuration
public class ZookeeperConfiguration implements ApplicationContextAware {

    private final Logger log = LoggerFactory.getLogger(ZookeeperConfiguration.class);

    private final String datasourcePath = "/datasource";

    private ApplicationContext context;

    @Value("${rpc.registry}")
    private String address;

    @Bean
    public ZkClient zkClient() {
        return new ZkClient(address, 60000);
    }

    @Bean(name = "dataSource")
    public DataSource dataSource() {
        ZkClient zkClient = zkClient();
        zkClient.subscribeDataChanges(datasourcePath, new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {

                DruidDataSource dataSource = (DruidDataSource) context.getBean("dataSource");

                /*Class<? extends DruidDataSource> dataSourceClass = dataSource.getClass();
                Field jdbcUrl = dataSourceClass.getField("jdbcUrl");
                jdbcUrl.setAccessible(true);
                jdbcUrl.set(dataSource, p.getUrl());
                Field username = dataSourceClass.getField("username");
                username.setAccessible(true);
                username.set(dataSource, p.getUsername());
                Field password = dataSourceClass.getField("password");
                password.setAccessible(true);
                password.set(dataSource, p.getPassword());
                Field driverClass = dataSourceClass.getField("driverClass");
                driverClass.setAccessible(true);
                driverClass.set(dataSource, p.getDriverClassName());*/
                if (dataSource != null) {
                    log.info("DruidDataSource will be destroy");
                    dataSource.close();
                }

                DataSourceProperties p = setDataSourceProperties(new DataSourceProperties(), o);
                DataSource newDataSource = p.initializeDataSourceBuilder().build();
                dataSource = (DruidDataSource) newDataSource;
            }

            @Override
            public void handleDataDeleted(String s) throws Exception {

            }
        });

        DataSourceProperties properties = new DataSourceProperties();
        Object o = zkClient.readData(datasourcePath);
        DataSourceProperties dataSourceProperties = setDataSourceProperties(properties, o);
        DataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().build();
        return dataSource;
    }

    private DataSourceProperties setDataSourceProperties(DataSourceProperties properties, Object o) {
        ZkDataSourceProperties sourceProperties = JSON.parseObject((byte[]) o, ZkDataSourceProperties.class);
        try {
            properties.setType((Class<? extends DataSource>) Class.forName(sourceProperties.getType()));
            properties.setDriverClassName(sourceProperties.getDriverClass());
            properties.setUrl(sourceProperties.getUrl());
            properties.setUsername(sourceProperties.getUsername());
            properties.setPassword(sourceProperties.getPassword());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return properties;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}
